package com.feinno.urcs.group.siptask;

import com.feinno.sip.header.CSeq;
import com.feinno.sip.header.CallID;
import com.feinno.sip.header.RouteList;
import com.feinno.sip.message.SipRequest;
import com.feinno.sip.message.SipResponse;
import com.feinno.sip.parser.RouteParser;
import com.feinno.sip.transaction.TransactionClient;
import com.feinno.sip.transaction.TransactionClientListener;
import com.feinno.urcs.group.GroupConfiguration;
import com.feinno.urcs.group.GroupConstants;
import com.feinno.urcs.group.api.GroupService;
import com.feinno.urcs.group.entity.GroupIndex;
import com.feinno.urcs.group.entity.GroupInfo;
import com.feinno.urcs.group.entity.GroupListNotifyInfo;
import com.feinno.urcs.group.siptask.task.GroupListNotifyArgs;
import com.feinno.urcs.group.siptask.task.GroupTaskEvents;
import com.feinno.urcs.sip.SipConnector;
import com.feinno.urcs.sip.UrcsSipFactory;
import com.feinno.urcs.sipservlet.SipConnectorLoader;
import com.feinno.urcs.sipservlet.SipServletFuture;
import com.feinno.urcs.sipservlet.SipServletRequest;
import com.feinno.urcs.sipservlet.SipServletRequestFactory;
import com.feinno.urcs.sipservlet.message.SipMessageBuilder;
import org.helium.framework.annotations.FieldSetter;
import org.helium.framework.annotations.ServiceSetter;
import org.helium.framework.annotations.TaskImplementation;
import org.helium.framework.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.address.TelURI;
import javax.sip.message.Request;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Li.Hongbo <lihongbo@feinno.com>
 */
@TaskImplementation(event = GroupTaskEvents.GROUP_LIST_NOTIFY)
public class GroupListNotifyTask implements Task<GroupListNotifyArgs> {
	private static final Logger LOGGER = LoggerFactory.getLogger(GroupListNotifyTask.class);

	@FieldSetter("${CSCF_ADDRESS}")
	private String cscfAddress;
	@FieldSetter(loader = SipConnectorLoader.class, value = "${SIP_STACK_AS}")
	private SipConnector connector;

	@ServiceSetter
	private GroupService groupService;


	@Override
	public void processTask(GroupListNotifyArgs args) {
		LOGGER.info("GroupInfoNotifyTask {} {}", args.getGroupInfo().getGroupId(), args.getToMemberMobileNo());
		try {
			SipServletRequest request = createGroupListNotify(args);
			SipServletFuture future = request.sendRequest();
			future.setListener(new TransactionClientListener() {
				@Override
				public void onTransProvisionalResponse(TransactionClient transactionClient, SipResponse sipResponse) {
					// 100 180
				}

				@Override
				public void onTransSuccessResponse(TransactionClient transactionClient, SipResponse sipResponse) {
					// 200

				}

				@Override
				public void onTransFailureResponse(TransactionClient transactionClient, SipResponse sipResponse) {
					// 4xx
					// 5xx
				}

				@Override
				public void onTransTimeout(TransactionClient transactionClient) {
					// TIMEOUT

				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public SipServletRequest createGroupListNotify(GroupListNotifyArgs args) throws Exception {

		List<Integer> groupList = groupService.getGroupList(args.getToMemberMobileNo());
		SipURI groupUri = UrcsSipFactory.getAddressFactory().createSipURI(GroupConfiguration.INSTANCE.getGroupPrefix() + args.getGroupInfo().getGroupId(), GroupConfiguration.INSTANCE.getGroupDomain());
		TelURI toTel = UrcsSipFactory.getAddressFactory().createTelURI(args.getToMemberMobileNo().toString());
		Address fromAddress = UrcsSipFactory.getAddressFactory().createAddress(groupUri);
		Address toAddress = UrcsSipFactory.getAddressFactory().createAddress(toTel);
		SipRequest sipRequest = UrcsSipFactory.getMessageFactory().createRequest(connector.getSipProvider(), Request.NOTIFY, toAddress, fromAddress);
		sipRequest.setFromTag(args.getFromTag());
		sipRequest.setToTag(args.getToTag());
		SipServletRequest sipServletRequest = SipServletRequestFactory.createRequest(sipRequest, connector);
		SipMessageBuilder builder = new SipMessageBuilder(sipServletRequest);
		builder.from(groupUri)
				.to(toTel)
				.fromTag(args.getFromTag())
				.toTag(args.getToTag())
//				.requestUri(UrcsSipFactory.getAddressFactory().createTelURI(args.getToMemberMobileNo().toString()))
				.requestUri(UrcsSipFactory.getAddressFactory().createAddress(args.getContact()).getURI())
				.removeHeader(CallID.NAME)
				.callId(args.getCallId())
				.removeHeader(CSeq.NAME)
				.cSeq(args.getCseq(), Request.NOTIFY)
				.pai(groupUri)
				.allow("INVITE,UPDATE,ACK,CANCEL,BYE,NOTIFY,OPTIONS,MESSAGE,REFER")
				.contact(groupUri.getUser(), groupUri.getHost(), GroupConstants.G_3GPP_ICSI_REF_SESSION_KEY_VALUE, true)
				.maxForwards(70)
				.supported("timer,recipient-list-invite")
//				.subscriptionState(args.getExpired()) // TODO
				.subscriptionState(0) // TODO
				.event("grouplist")
				.allowEvents("conference,grouplist")
				.accept("application", "sdp")
				.userAgent("Conf-serv/3GPP");
		byte[] groupListNotifyXml = createGroupListNotifyXml(groupList, args.getToMemberMobileNo().toAddress().getURI().toString());
		if (groupListNotifyXml.length >= 13 * 1024) {
			builder.gzipContent(groupListNotifyXml, "application", "conference-info+xml");
		} else {
			builder.content(groupListNotifyXml, "application", "conference-info+xml");
		}
		if (args.getRoute().size() > 0) {
			for (String r : args.getRoute()) {
				RouteList routes = (RouteList) new RouteParser(r).parse();
				if (routes.size() > 0) {
					routes.forEach(builder::addHeader);
				}
			}
		}

		SipServletRequest notify = builder.toSipServletReqeust();

		return notify;
	}

	private byte[] createGroupListNotifyXml(List<Integer> groupList, String uri) throws Exception {
		GroupListNotifyInfo notifyInfo = new GroupListNotifyInfo();
		notifyInfo.setEntity(uri);
		notifyInfo.setXmlns("urn:ietf:params:xml:ns:conference-info");
		notifyInfo.setState("list");
		GroupListNotifyInfo.ConferenceList conferenceList = new GroupListNotifyInfo.ConferenceList();
		GroupListNotifyInfo.GroupListVer groupListVer = new GroupListNotifyInfo.GroupListVer();
		groupListVer.setVersion("0");
		conferenceList.setGroupListVer(groupListVer);
		List<GroupListNotifyInfo.GroupListInfo> groupListInfos = new ArrayList<GroupListNotifyInfo.GroupListInfo>();
		for (int groupId : groupList) {
			GroupListNotifyInfo.GroupListInfo groupListInfo = new GroupListNotifyInfo.GroupListInfo();
			GroupIndex index = groupService.getGroupIndex(groupId);
			groupListInfo.setEntity(index.getConferenceUri());
			// TODO 此处应该调用群列表服务器，当前先走groupservice
			GroupInfo groupInfo = groupService.getGroupInfo(index);
			groupListInfo.setConversationid(groupInfo.getConversationId());
			groupListInfo.setName(groupInfo.getSubject());
			groupListInfos.add(groupListInfo);
		}
		conferenceList.setGrouplistInfos(groupListInfos);
		notifyInfo.setConferenceList(conferenceList);
		return notifyInfo.toXmlByteArray();
	}
}
